!-------------------------------------------------------------LICENSE--------------------------------------------------------------!
!                                                                                                                                  !
!The MAP code is written in Fortran language for magnetohydrodynamics (MHD) calculation with the adaptive mesh refinement (AMR)    !
!and Message Passing Interface (MPI) parallelization.                                                                              !
!                                                                                                                                  !
!Copyright (C) 2012                                                                                                                !
!Ronglin Jiang                                                                                                                     !
!rljiang@ssc.net.cn                                                                                                                !
!585 Guoshoujing Road. Pudong, Shanghai, P.R.C. 201203                                                                             !
!                                                                                                                                  !
!This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License         !
!as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.             !
!                                                                                                                                  !
!This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of    !
!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.                        !
!                                                                                                                                  !
!You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software     !
!Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.                                                   !
!                                                                                                                                  !
!-------------------------------------------------------------LICENSE--------------------------------------------------------------!

!==================================================================================================================================|
subroutine memory_usage(base)
!==================================================================================================================================|

   use parameters
   use block_define

   implicit none
   type(block), pointer, intent(in) :: base

   integer(8) :: size_block_var, size_block_bnd, n_block_var, n_block_bnd, size_parameter, n_block_var_net
   integer(8) :: size_block_var_global, size_block_bnd_global, n_block_var_global, n_block_bnd_global, size_parameter_global

   type(block), pointer :: current

!----------------------------------------------------------------------------------------------------------------------------------|

   size_parameter = 0
   size_parameter = size_parameter + size(neighs_reflux_send_x)
   size_parameter = size_parameter + size(neighs_reflux_send_y)
   size_parameter = size_parameter + size(neighs_reflux_send_z)
   size_parameter = size_parameter + size(neighs_reflux_recv_x)
   size_parameter = size_parameter + size(neighs_reflux_recv_y)
   size_parameter = size_parameter + size(neighs_reflux_recv_z)
   size_parameter = size_parameter + size(neighs_shareblock_send_x)
   size_parameter = size_parameter + size(neighs_shareblock_send_y)
   size_parameter = size_parameter + size(neighs_shareblock_send_z)
   size_parameter = size_parameter + size(neighs_shareblock_recv_x)
   size_parameter = size_parameter + size(neighs_shareblock_recv_y)
   size_parameter = size_parameter + size(neighs_shareblock_recv_z)
   size_parameter = size_parameter + size(neighs_exchange_send_x)
   size_parameter = size_parameter + size(neighs_exchange_send_y)
   size_parameter = size_parameter + size(neighs_exchange_send_z)
   size_parameter = size_parameter + size(neighs_exchange_recv_x)
   size_parameter = size_parameter + size(neighs_exchange_recv_y)
   size_parameter = size_parameter + size(neighs_exchange_recv_z)

   size_block_var = 0
   size_block_bnd = 0
   n_block_var_net = 0
   n_block_var = 0
   n_block_bnd = 0

   current => base%framework_next
   do while (current%lv .ne. 0)
      if (allocated(current%ro)) then
         size_block_var = size_block_var + size(current%ro)
         size_block_var = size_block_var + size(current%mx)
         size_block_var = size_block_var + size(current%my)
         size_block_var = size_block_var + size(current%mz)
         size_block_var = size_block_var + size(current%bx)
         size_block_var = size_block_var + size(current%by)
         size_block_var = size_block_var + size(current%bz)
         size_block_var = size_block_var + size(current%en)
         size_block_var = size_block_var + size(current%gx)
         size_block_var = size_block_var + size(current%gy)
         size_block_var = size_block_var + size(current%gz)
         size_block_var = size_block_var + size(current%po)
         if (ini_value_save_flag .ne. 0) then
            size_block_var = size_block_var + size(current%ro0)
            size_block_var = size_block_var + size(current%mx0)
            size_block_var = size_block_var + size(current%my0)
            size_block_var = size_block_var + size(current%mz0)
            size_block_var = size_block_var + size(current%bx0)
            size_block_var = size_block_var + size(current%by0)
            size_block_var = size_block_var + size(current%bz0)
            size_block_var = size_block_var + size(current%en0)
         endif
         n_block_var = n_block_var + 1
         if (cpu_id .eq. current%cpu_id) n_block_var_net = n_block_var_net + 1
      endif

      if (allocated(current%fxro_bnd)) then
         size_block_bnd = size_block_bnd + size(current%fxro_bnd)
         size_block_bnd = size_block_bnd + size(current%fxmx_bnd)
         size_block_bnd = size_block_bnd + size(current%fxmy_bnd)
         size_block_bnd = size_block_bnd + size(current%fxmz_bnd)
         size_block_bnd = size_block_bnd + size(current%fxbx_bnd)
         size_block_bnd = size_block_bnd + size(current%fxby_bnd)
         size_block_bnd = size_block_bnd + size(current%fxbz_bnd)
         size_block_bnd = size_block_bnd + size(current%fxen_bnd)
         size_block_bnd = size_block_bnd + size(current%fxpo_bnd)
         size_block_bnd = size_block_bnd + size(current%fyro_bnd)
         size_block_bnd = size_block_bnd + size(current%fymx_bnd)
         size_block_bnd = size_block_bnd + size(current%fymy_bnd)
         size_block_bnd = size_block_bnd + size(current%fymz_bnd)
         size_block_bnd = size_block_bnd + size(current%fybx_bnd)
         size_block_bnd = size_block_bnd + size(current%fyby_bnd)
         size_block_bnd = size_block_bnd + size(current%fybz_bnd)
         size_block_bnd = size_block_bnd + size(current%fyen_bnd)
         size_block_bnd = size_block_bnd + size(current%fypo_bnd)
         size_block_bnd = size_block_bnd + size(current%fzro_bnd)
         size_block_bnd = size_block_bnd + size(current%fzmx_bnd)
         size_block_bnd = size_block_bnd + size(current%fzmy_bnd)
         size_block_bnd = size_block_bnd + size(current%fzmz_bnd)
         size_block_bnd = size_block_bnd + size(current%fzbx_bnd)
         size_block_bnd = size_block_bnd + size(current%fzby_bnd)
         size_block_bnd = size_block_bnd + size(current%fzbz_bnd)
         size_block_bnd = size_block_bnd + size(current%fzen_bnd)
         size_block_bnd = size_block_bnd + size(current%fzpo_bnd)
         n_block_bnd = n_block_bnd + 1
      endif

      current => current%framework_next
   enddo

   call mpi_allreduce(size_parameter, size_parameter_global, 1, mpi_integer8, mpi_sum, mpi_comm_world, error)
   call mpi_allreduce(n_block_var, n_block_var_global, 1, mpi_integer8, mpi_sum, mpi_comm_world, error)
   call mpi_allreduce(size_block_var, size_block_var_global, 1, mpi_integer8, mpi_sum, mpi_comm_world, error)
   call mpi_allreduce(n_block_bnd, n_block_bnd_global, 1, mpi_integer8, mpi_sum, mpi_comm_world, error)
   call mpi_allreduce(size_block_bnd, size_block_bnd_global, 1, mpi_integer8, mpi_sum, mpi_comm_world, error)

   if (cpu_id .eq. 0) then
!      write(*, *) "gene:"
!      write(*, *) shape(gene)
!      write(*, *) 1.0d0 * size(gene) * 4 / 1024 / 1024, ' MB'
!      size_parameter = size_parameter + size(gene)

!      write(*, *) "neighs_reflux_send_x:"
!      write(*, *) shape(neighs_reflux_send_x)
!      write(*, *) 1.0d0 * size(neighs_reflux_send_x) * 8 / 1024 / 1024, ' MB'

!      write(*, *) "neighs_reflux_send_y:"
!      write(*, *) shape(neighs_reflux_send_y)
!      write(*, *) 1.0d0 * size(neighs_reflux_send_y) * 8 / 1024 / 1024, ' MB'

!      write(*, *) "neighs_reflux_send_z:"
!      write(*, *) shape(neighs_reflux_send_z)
!      write(*, *) 1.0d0 * size(neighs_reflux_send_z) * 8 / 1024 / 1024, ' MB'

!      write(*, *) "neighs_reflux_recv_x:"
!      write(*, *) shape(neighs_reflux_recv_x)
!      write(*, *) 1.0d0 * size(neighs_reflux_recv_x) * 8 / 1024 / 1024, ' MB'

!      write(*, *) "neighs_reflux_recv_y:"
!      write(*, *) shape(neighs_reflux_recv_y)
!      write(*, *) 1.0d0 * size(neighs_reflux_recv_y) * 8 / 1024 / 1024, ' MB'

!      write(*, *) "neighs_reflux_recv_z:"
!      write(*, *) shape(neighs_reflux_recv_z)
!      write(*, *) 1.0d0 * size(neighs_reflux_recv_z) * 8 / 1024 / 1024, ' MB'

!      write(*, *) "neighs_shareblock_send_x:"
!      write(*, *) shape(neighs_shareblock_send_x)
!      write(*, *) 1.0d0 * size(neighs_shareblock_send_x) * 8 / 1024 / 1024, ' MB'

!      write(*, *) "neighs_shareblock_send_y:"
!      write(*, *) shape(neighs_shareblock_send_y)
!      write(*, *) 1.0d0 * size(neighs_shareblock_send_y) * 8 / 1024 / 1024, ' MB'

!      write(*, *) "neighs_shareblock_send_z:"
!      write(*, *) shape(neighs_shareblock_send_z)
!      write(*, *) 1.0d0 * size(neighs_shareblock_send_z) * 8 / 1024 / 1024, ' MB'

!      write(*, *) "neighs_shareblock_recv_x:"
!      write(*, *) shape(neighs_shareblock_recv_x)
!      write(*, *) 1.0d0 * size(neighs_shareblock_recv_x) * 8 / 1024 / 1024, ' MB'

!      write(*, *) "neighs_shareblock_recv_y:"
!      write(*, *) shape(neighs_shareblock_recv_y)
!      write(*, *) 1.0d0 * size(neighs_shareblock_recv_y) * 8 / 1024 / 1024, ' MB'

!      write(*, *) "neighs_shareblock_recv_z:"
!      write(*, *) shape(neighs_shareblock_recv_z)
!      write(*, *) 1.0d0 * size(neighs_shareblock_recv_z) * 8 / 1024 / 1024, ' MB'

!      write(*, *) "neighs_exchange_send_x:"
!      write(*, *) shape(neighs_exchange_send_x)
!      write(*, *) 1.0d0 * size(neighs_exchange_send_x) * 8 / 1024 / 1024, ' MB'

!      write(*, *) "neighs_exchange_send_y:"
!      write(*, *) shape(neighs_exchange_send_y)
!      write(*, *) 1.0d0 * size(neighs_exchange_send_y) * 8 / 1024 / 1024, ' MB'

!      write(*, *) "neighs_exchange_send_z:"
!      write(*, *) shape(neighs_exchange_send_z)
!      write(*, *) 1.0d0 * size(neighs_exchange_send_z) * 8 / 1024 / 1024, ' MB'

!      write(*, *) "neighs_exchange_recv_x:"
!      write(*, *) shape(neighs_exchange_recv_x)
!      write(*, *) 1.0d0 * size(neighs_exchange_recv_x) * 8 / 1024 / 1024, ' MB'

!      write(*, *) "neighs_exchange_recv_y:"
!      write(*, *) shape(neighs_exchange_recv_y)
!      write(*, *) 1.0d0 * size(neighs_exchange_recv_y) * 8 / 1024 / 1024, ' MB'

!      write(*, *) "neighs_exchange_recv_z:"
!      write(*, *) shape(neighs_exchange_recv_z)
!      write(*, *) 1.0d0 * size(neighs_exchange_recv_z) * 8 / 1024 / 1024, ' MB'

      write(*, *) 
      write(*, *) "size_parameter:"
      write(*, *) 1.0d0 * size_parameter * 8 / 1024 / 1024, ' MB'
      write(*, *) "block var:"
      write(*, *) 1.0d0 * size_block_var * 8 / 1024 / 1024, ' MB'
      write(*, *) "block bnd:"
      write(*, *) 1.0d0 * size_block_bnd * 8 / 1024 / 1024, ' MB'
      write(*, *) "number of blocks belong to current CPU:", n_block_var_net
      write(*, *) "number of blocks which are allocated memory:", n_block_var

      write(*, *) 
      write(*, *) "size_parameter_global:"
      write(*, *) 1.0d0 * size_parameter_global * 8 / 1024 / 1024, ' MB'
      write(*, *) "block var_global:"
      write(*, *) 1.0d0 * size_block_var_global * 8 / 1024 / 1024, ' MB'
      write(*, *) "block bnd_global:"
      write(*, *) 1.0d0 * size_block_bnd_global * 8 / 1024 / 1024, ' MB'
      write(*, *)
      write(*, *) "n_blocks_all:", n_blocks_all, '  processors:', cpu_number
      write(*, *) "size:", 1.0d0 * n_blocks_all * nx_block * ny_block * nz_block * 12 * 8 / 1024 / 1024, ' MB'
      write(*, *)
!      pause
   endif

!----------------------------------------------------------------------------------------------------------------------------------|
   return
end subroutine memory_usage
